بر انواع ابزاری TypeScript مسلط شوید: ابزارهایی قدرتمند برای تبدیل انواع، بهبود قابلیت استفاده مجدد کد و افزایش ایمنی نوع در برنامههایتان.
انواع ابزاری TypeScript: ابزارهای داخلی برای دستکاری نوع
تایپاسکریپت یک زبان قدرتمند است که تایپدهی استاتیک را به جاوااسکریپت میآورد. یکی از ویژگیهای کلیدی آن، قابلیت دستکاری انواع است که به توسعهدهندگان اجازه میدهد کدهای قویتر و قابل نگهداریتری ایجاد کنند. تایپاسکریپت مجموعهای از انواع ابزاری داخلی را ارائه میدهد که تبدیلهای رایج انواع را ساده میکنند. این انواع ابزاری، ابزارهای ارزشمندی برای افزایش ایمنی نوع، بهبود قابلیت استفاده مجدد کد و بهینهسازی جریان کار توسعه شما هستند. این راهنمای جامع به بررسی ضروریترین انواع ابزاری تایپاسکریپت میپردازد و مثالهای عملی و بینشهای کاربردی برای کمک به شما در تسلط بر آنها ارائه میدهد.
انواع ابزاری TypeScript چه هستند؟
انواع ابزاری، عملگرهای نوع از پیش تعریفشدهای هستند که انواع موجود را به انواع جدید تبدیل میکنند. آنها در زبان تایپاسکریپت تعبیه شدهاند و روشی مختصر و اعلانی برای انجام دستکاریهای رایج نوع فراهم میکنند. استفاده از انواع ابزاری میتواند به طور قابل توجهی کدهای تکراری را کاهش دهد و تعاریف نوع شما را گویاتر و قابل فهمتر کند.
آنها را مانند توابعی در نظر بگیرید که به جای مقادیر، بر روی انواع عمل میکنند. آنها یک نوع را به عنوان ورودی میگیرند و یک نوع اصلاحشده را به عنوان خروجی برمیگردانند. این به شما امکان میدهد تا روابط و تبدیلهای پیچیده نوع را با حداقل کد ایجاد کنید.
چرا از انواع ابزاری استفاده کنیم؟
چندین دلیل قانعکننده برای گنجاندن انواع ابزاری در پروژههای تایپاسکریپت شما وجود دارد:
- افزایش ایمنی نوع: انواع ابزاری به شما کمک میکنند تا محدودیتهای نوع سختگیرانهتری را اعمال کنید، که احتمال خطاهای زمان اجرا را کاهش داده و قابلیت اطمینان کلی کد شما را بهبود میبخشد.
- بهبود قابلیت استفاده مجدد کد: با استفاده از انواع ابزاری، میتوانید کامپوننتها و توابع جنریک بسازید که با انواع مختلفی کار میکنند و این باعث ترویج استفاده مجدد از کد و کاهش افزونگی میشود.
- کاهش کدهای تکراری: انواع ابزاری روشی مختصر و اعلانی برای انجام تبدیلهای رایج نوع فراهم میکنند و میزان کدهای تکراری که باید بنویسید را کاهش میدهند.
- خوانایی بهتر: انواع ابزاری تعاریف نوع شما را گویاتر و قابل فهمتر میکنند و خوانایی و قابلیت نگهداری کد شما را بهبود میبخشند.
انواع ابزاری ضروری TypeScript
بیایید برخی از رایجترین و مفیدترین انواع ابزاری در تایپاسکریپت را بررسی کنیم. ما هدف، سینتکس و مثالهای عملی آنها را برای نشان دادن کاربردشان پوشش خواهیم داد.
1. Partial<T>
نوع ابزاری Partial<T>
تمام خصوصیات نوع T
را اختیاری میکند. این زمانی مفید است که میخواهید یک نوع جدید ایجاد کنید که برخی یا تمام خصوصیات یک نوع موجود را داشته باشد، اما نمیخواهید همه آنها الزامی باشند.
سینتکس:
type Partial<T> = { [P in keyof T]?: T[P]; };
مثال:
interface User {
id: number;
name: string;
email: string;
}
type OptionalUser = Partial<User>; // همه خصوصیات اکنون اختیاری هستند
const partialUser: OptionalUser = {
name: "Alice", // فقط خصوصیت name ارائه شده است
};
مورد استفاده: بهروزرسانی یک شیء فقط با برخی از خصوصیات. به عنوان مثال، یک فرم بهروزرسانی پروفایل کاربر را تصور کنید. شما نمیخواهید کاربران را ملزم کنید که همه فیلدها را یکباره بهروز کنند.
2. Required<T>
نوع ابزاری Required<T>
تمام خصوصیات نوع T
را الزامی میکند. این برعکس Partial<T>
است. این زمانی مفید است که شما یک نوع با خصوصیات اختیاری دارید و میخواهید اطمینان حاصل کنید که تمام خصوصیات وجود دارند.
سینتکس:
type Required<T> = { [P in keyof T]-?: T[P]; };
مثال:
interface Config {
apiKey?: string;
apiUrl?: string;
}
type CompleteConfig = Required<Config>; // همه خصوصیات اکنون الزامی هستند
const config: CompleteConfig = {
apiKey: "your-api-key",
apiUrl: "https://example.com/api",
};
مورد استفاده: اطمینان از اینکه تمام تنظیمات پیکربندی قبل از شروع برنامه ارائه شدهاند. این میتواند به جلوگیری از خطاهای زمان اجرا ناشی از تنظیمات گمشده یا تعریف نشده کمک کند.
3. Readonly<T>
نوع ابزاری Readonly<T>
تمام خصوصیات نوع T
را فقط خواندنی (readonly) میکند. این از تغییر تصادفی خصوصیات یک شیء پس از ایجاد آن جلوگیری میکند. این کار تغییرناپذیری (immutability) را ترویج داده و پیشبینیپذیری کد شما را بهبود میبخشد.
سینتکس:
type Readonly<T> = { readonly [P in keyof T]: T[P]; };
مثال:
interface Product {
id: number;
name: string;
price: number;
}
type ImmutableProduct = Readonly<Product>; // همه خصوصیات اکنون فقط خواندنی هستند
const product: ImmutableProduct = {
id: 123,
name: "Example Product",
price: 25.99,
};
// product.price = 29.99; // خطا: نمیتوان به 'price' مقدار اختصاص داد زیرا یک خصوصیت فقط خواندنی است.
مورد استفاده: ایجاد ساختارهای داده تغییرناپذیر، مانند اشیاء پیکربندی یا اشیاء انتقال داده (DTOs)، که نباید پس از ایجاد تغییر کنند. این به ویژه در پارادایمهای برنامهنویسی تابعی مفید است.
4. Pick<T, K extends keyof T>
نوع ابزاری Pick<T, K extends keyof T>
با انتخاب مجموعهای از خصوصیات K
از نوع T
یک نوع جدید ایجاد میکند. این زمانی مفید است که شما فقط به زیرمجموعهای از خصوصیات یک نوع موجود نیاز دارید.
سینتکس:
type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
مثال:
interface Employee {
id: number;
name: string;
department: string;
salary: number;
}
type EmployeeNameAndDepartment = Pick<Employee, "name" | "department">; // فقط name و department را انتخاب کن
const employeeInfo: EmployeeNameAndDepartment = {
name: "Bob",
department: "Engineering",
};
مورد استفاده: ایجاد اشیاء انتقال داده (DTOs) تخصصی که فقط شامل دادههای لازم برای یک عملیات خاص هستند. این میتواند عملکرد را بهبود بخشد و میزان دادههای منتقل شده از طریق شبکه را کاهش دهد. تصور کنید جزئیات کاربر را به کلاینت ارسال میکنید اما اطلاعات حساس مانند حقوق را حذف میکنید. میتوانید از Pick برای ارسال فقط `id` و `name` استفاده کنید.
5. Omit<T, K extends keyof any>
نوع ابزاری Omit<T, K extends keyof any>
با حذف مجموعهای از خصوصیات K
از نوع T
یک نوع جدید ایجاد میکند. این برعکس Pick<T, K extends keyof T>
است و زمانی مفید است که میخواهید خصوصیات خاصی را از یک نوع موجود حذف کنید.
سینتکس:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
مثال:
interface Event {
id: number;
title: string;
description: string;
date: Date;
location: string;
}
type EventSummary = Omit<Event, "description" | "location">; // description و location را حذف کن
const eventPreview: EventSummary = {
id: 1,
title: "Conference",
date: new Date(),
};
مورد استفاده: ایجاد نسخههای سادهشده از مدلهای داده برای اهداف خاص، مانند نمایش خلاصهای از یک رویداد بدون شامل شدن توضیحات کامل و مکان. این همچنین میتواند برای حذف فیلدهای حساس قبل از ارسال داده به کلاینت استفاده شود.
6. Exclude<T, U>
نوع ابزاری Exclude<T, U>
با حذف تمام انواعی از T
که به U
قابل انتساب هستند، یک نوع جدید ایجاد میکند. این زمانی مفید است که میخواهید انواع خاصی را از یک نوع union حذف کنید.
سینتکس:
type Exclude<T, U> = T extends U ? never : T;
مثال:
type AllowedFileTypes = "image" | "video" | "audio" | "document";
type MediaFileTypes = "image" | "video" | "audio";
type DocumentFileTypes = Exclude<AllowedFileTypes, MediaFileTypes>; // "document"
const fileType: DocumentFileTypes = "document";
مورد استفاده: فیلتر کردن یک نوع union برای حذف انواع خاصی که در یک زمینه خاص مرتبط نیستند. به عنوان مثال، ممکن است بخواهید انواع فایل خاصی را از لیستی از انواع فایل مجاز حذف کنید.
7. Extract<T, U>
نوع ابزاری Extract<T, U>
با استخراج تمام انواعی از T
که به U
قابل انتساب هستند، یک نوع جدید ایجاد میکند. این برعکس Exclude<T, U>
است و زمانی مفید است که میخواهید انواع خاصی را از یک نوع union انتخاب کنید.
سینتکس:
type Extract<T, U> = T extends U ? T : never;
مثال:
type InputTypes = string | number | boolean | null | undefined;
type PrimitiveTypes = string | number | boolean;
type NonNullablePrimitives = Extract<InputTypes, PrimitiveTypes>; // string | number | boolean
const value: NonNullablePrimitives = "hello";
مورد استفاده: انتخاب انواع خاص از یک نوع union بر اساس معیارهای خاص. به عنوان مثال، ممکن است بخواهید تمام انواع اولیه (primitive) را از یک نوع union که شامل انواع اولیه و انواع شیء است، استخراج کنید.
8. NonNullable<T>
نوع ابزاری NonNullable<T>
با حذف null
و undefined
از نوع T
یک نوع جدید ایجاد میکند. این زمانی مفید است که میخواهید اطمینان حاصل کنید که یک نوع نمیتواند null
یا undefined
باشد.
سینتکس:
type NonNullable<T> = T extends null | undefined ? never : T;
مثال:
type MaybeString = string | null | undefined;
type DefinitelyString = NonNullable<MaybeString>; // string
const message: DefinitelyString = "Hello, world!";
مورد استفاده: اطمینان از اینکه یک مقدار قبل از انجام عملیات روی آن null
یا undefined
نیست. این میتواند به جلوگیری از خطاهای زمان اجرا ناشی از مقادیر غیرمنتظره null یا undefined کمک کند. سناریویی را در نظر بگیرید که نیاز به پردازش آدرس کاربر دارید و حیاتی است که آدرس قبل از هر عملیاتی null نباشد.
9. ReturnType<T extends (...args: any) => any>
نوع ابزاری ReturnType<T extends (...args: any) => any>
نوع بازگشتی یک نوع تابع T
را استخراج میکند. این زمانی مفید است که میخواهید نوع مقداری را که یک تابع برمیگرداند، بدانید.
سینتکس:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
مثال:
function fetchData(url: string): Promise<{ data: any }> {
return fetch(url).then(response => response.json());
}
type FetchDataReturnType = ReturnType<typeof fetchData>; // Promise<{ data: any }>
async function processData(data: FetchDataReturnType) {
// ...
}
مورد استفاده: تعیین نوع مقدار بازگشتی توسط یک تابع، به ویژه هنگام کار با عملیاتهای ناهمزمان یا امضاهای پیچیده توابع. این به شما امکان میدهد تا اطمینان حاصل کنید که مقدار بازگشتی را به درستی مدیریت میکنید.
10. Parameters<T extends (...args: any) => any>
نوع ابزاری Parameters<T extends (...args: any) => any>
انواع پارامترهای یک نوع تابع T
را به صورت یک تاپل (tuple) استخراج میکند. این زمانی مفید است که میخواهید انواع آرگومانهایی را که یک تابع میپذیرد، بدانید.
سینتکس:
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
مثال:
function createUser(name: string, age: number, email: string): void {
// ...
}
type CreateUserParams = Parameters<typeof createUser>; // [string, number, string]
function logUser(...args: CreateUserParams) {
console.log("Creating user with:", args);
}
مورد استفاده: تعیین انواع آرگومانهایی که یک تابع میپذیرد، که میتواند برای ایجاد توابع جنریک یا دکوراتورهایی که باید با توابع با امضاهای مختلف کار کنند، مفید باشد. این به تضمین ایمنی نوع هنگام ارسال پویا آرگومانها به یک تابع کمک میکند.
11. ConstructorParameters<T extends abstract new (...args: any) => any>
نوع ابزاری ConstructorParameters<T extends abstract new (...args: any) => any>
انواع پارامترهای یک نوع تابع سازنده (constructor) T
را به صورت یک تاپل استخراج میکند. این زمانی مفید است که میخواهید انواع آرگومانهایی را که یک سازنده میپذیرد، بدانید.
سینتکس:
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
مثال:
class Logger {
constructor(public prefix: string, public enabled: boolean) {}
log(message: string) {
if (this.enabled) {
console.log(`${this.prefix}: ${message}`);
}
}
}
type LoggerConstructorParams = ConstructorParameters<typeof Logger>; // [string, boolean]
function createLogger(...args: LoggerConstructorParams) {
return new Logger(...args);
}
مورد استفاده: مشابه Parameters
، اما به طور خاص برای توابع سازنده. این هنگام ایجاد فکتوریها یا سیستمهای تزریق وابستگی که در آنها نیاز به نمونهسازی پویا از کلاسها با امضاهای سازنده مختلف دارید، کمک میکند.
12. InstanceType<T extends abstract new (...args: any) => any>
نوع ابزاری InstanceType<T extends abstract new (...args: any) => any>
نوع نمونه (instance type) یک نوع تابع سازنده T
را استخراج میکند. این زمانی مفید است که میخواهید نوع شیئی را که یک سازنده ایجاد میکند، بدانید.
سینتکس:
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
مثال:
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
type GreeterInstance = InstanceType<typeof Greeter>; // Greeter
const myGreeter: GreeterInstance = new Greeter("World");
console.log(myGreeter.greet());
مورد استفاده: تعیین نوع شیء ایجاد شده توسط یک سازنده، که هنگام کار با وراثت یا چندریختی (polymorphism) مفید است. این یک روش ایمن از نظر نوع برای ارجاع به نمونه یک کلاس فراهم میکند.
13. Record<K extends keyof any, T>
نوع ابزاری Record<K extends keyof any, T>
یک نوع شیء میسازد که کلیدهای خصوصیات آن K
و مقادیر خصوصیات آن T
هستند. این برای ایجاد انواع شبه-دیکشنری که کلیدهای آن را از قبل میدانید، مفید است.
سینتکس:
type Record<K extends keyof any, T> = { [P in K]: T; };
مثال:
type CountryCode = "US" | "CA" | "GB" | "DE";
type CurrencyMap = Record<CountryCode, string>; // { US: string; CA: string; GB: string; DE: string; }
const currencies: CurrencyMap = {
US: "USD",
CA: "CAD",
GB: "GBP",
DE: "EUR",
};
مورد استفاده: ایجاد اشیاء شبه-دیکشنری که در آن مجموعهای ثابت از کلیدها را دارید و میخواهید اطمینان حاصل کنید که همه کلیدها مقادیری از یک نوع خاص دارند. این در هنگام کار با فایلهای پیکربندی، نگاشت دادهها یا جداول جستجو رایج است.
انواع ابزاری سفارشی
در حالی که انواع ابزاری داخلی تایپاسکریپت قدرتمند هستند، شما همچنین میتوانید انواع ابزاری سفارشی خود را برای پاسخگویی به نیازهای خاص پروژههایتان ایجاد کنید. این به شما امکان میدهد تا تبدیلهای پیچیده نوع را کپسوله کرده و در سراسر کدبیس خود از آنها استفاده مجدد کنید.
مثال:
// یک نوع ابزاری برای دریافت کلیدهای یک شیء که نوع خاصی دارند
type KeysOfType<T, U> = { [K in keyof T]: T[K] extends U ? K : never }[keyof T];
interface Person {
name: string;
age: number;
address: string;
phoneNumber: number;
}
type StringKeys = KeysOfType<Person, string>; // "name" | "address"
بهترین شیوهها برای استفاده از انواع ابزاری
- از نامهای توصیفی استفاده کنید: به انواع ابزاری خود نامهای معناداری بدهید که هدف آنها را به وضوح نشان دهد. این خوانایی و قابلیت نگهداری کد شما را بهبود میبخشد.
- انواع ابزاری خود را مستند کنید: کامنتهایی اضافه کنید تا توضیح دهید انواع ابزاری شما چه کاری انجام میدهند و چگونه باید استفاده شوند. این به سایر توسعهدهندگان کمک میکند تا کد شما را بفهمند و به درستی از آن استفاده کنند.
- ساده نگه دارید: از ایجاد انواع ابزاری بیش از حد پیچیده که درک آنها دشوار است، خودداری کنید. تبدیلهای پیچیده را به انواع ابزاری کوچکتر و قابل مدیریتتر تقسیم کنید.
- انواع ابزاری خود را تست کنید: تستهای واحد بنویسید تا اطمینان حاصل کنید که انواع ابزاری شما به درستی کار میکنند. این به جلوگیری از خطاهای غیرمنتظره کمک میکند و تضمین میکند که انواع شما همانطور که انتظار میرود رفتار میکنند.
- عملکرد را در نظر بگیرید: در حالی که انواع ابزاری معمولاً تأثیر عملکرد قابل توجهی ندارند، به پیچیدگی تبدیلهای نوع خود، به ویژه در پروژههای بزرگ، توجه داشته باشید.
نتیجهگیری
انواع ابزاری تایپاسکریپت ابزارهای قدرتمندی هستند که میتوانند به طور قابل توجهی ایمنی نوع، قابلیت استفاده مجدد و قابلیت نگهداری کد شما را بهبود بخشند. با تسلط بر این انواع ابزاری، میتوانید برنامههای تایپاسکریپت قویتر و گویاتری بنویسید. این راهنما ضروریترین انواع ابزاری تایپاسکریپت را پوشش داده و مثالهای عملی و بینشهای کاربردی برای کمک به شما در ادغام آنها در پروژههایتان ارائه کرده است.
به یاد داشته باشید که با این انواع ابزاری آزمایش کنید و بررسی کنید که چگونه میتوانند برای حل مشکلات خاص در کد خودتان استفاده شوند. هرچه بیشتر با آنها آشنا شوید، بیشتر از آنها برای ایجاد برنامههای تایپاسکریپت تمیزتر، قابل نگهداریتر و ایمنتر از نظر نوع استفاده خواهید کرد. چه در حال ساخت برنامههای وب، برنامههای سمت سرور یا هر چیز دیگری باشید، انواع ابزاری مجموعه ارزشمندی از ابزارها را برای بهبود جریان کار توسعه و کیفیت کد شما فراهم میکنند. با استفاده از این ابزارهای داخلی دستکاری نوع، میتوانید پتانسیل کامل تایپاسکریپت را آزاد کرده و کدی بنویسید که هم گویا و هم قوی باشد.